//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Extensibility;

namespace OpenLS.Spreadsheet.Functions
{
#if DEBUG
    [ContractClass(typeof (FunctionContract))]
#endif
    public abstract class Function
    {
        public virtual string Name // TODO do something better;
        {
            get
            {
                return GetType().Name.Replace("Function", "").ToUpper();
            }
        }
#if DEBUG
        [ContractClassFor(typeof (Function))]
        abstract class FunctionContract: Function
        {
            internal override bool UsesVar
            {
                get
                {
                    Contract.Ensures(!(Contract.Result<bool>() && this.Name == "ISERROR"));
                    Contract.Ensures(!(!Contract.Result<bool>() && this.Name == "SEARCH"));
                    throw new NotSupportedException();
                }
            }
        }
#endif
        internal abstract bool UsesVar { get; }
        public abstract string LocalizedName { get; }
        internal abstract bool NoValueAccess{ get;}
        protected static List<object> RangeToDouble(CellsRange r)
        {
            List<object> result = new List<object>();
            foreach (Cell c in r.GetAllCells())
                result.Add(c.Value);
            return result;
        }

        protected object InvokeOld(Cell caller, Worksheet worksheet , Workbook workbook, object[] args)
        {
            try
            {
                return InvokeImp(caller, worksheet, workbook, args);
            }
                catch (NullReferenceException)
                {
                    throw;
                }
            catch (ErrorException ee)
            {
                // Contract.Assert(false);
                return ee.Error;
            }
            catch (Exception e)
            {
                Exception ee = e;
                while (ee != null)
                {
                    if (ee is ErrorException)
                        return ((ErrorException)ee).Error;
                    ee = ee.InnerException;
                }
                return Errors.ValueError;
            }
        }

        protected abstract object InvokeImp(Cell caller, Worksheet worksheet, Workbook workbook, object[] args);



        internal virtual object Invoke(EvaluationContext context, List<Expression> arguments)
        {
            object[] actualArguments = new object[arguments.Count];
            for (int i = 0; i < actualArguments.Length; i++)
                actualArguments[i] = arguments[i].GetObject(context);
            return InvokeOld(context.Target, context.Worksheet, context.Workbook, actualArguments);
        }
        internal abstract int MaximumParameterCount { get;}
    }
}
